package BaseClasses;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

/**
 * Classe usada para guardar e calcular informação relativa a uma interface
 * 
 */
public class DataInterface {

    private int oidInterface;
    private String nome;
    private String estado;
    private long larguraBandaNominal;
    private float pollingTime;
    private ArrayList<PairTimeValue> ultimaHora;
    private ArrayList<PairTimeValue> ultimoMinuto;

    /**
     * 
     */
    public DataInterface() {
        this.oidInterface = 0;
        this.nome = "";
        this.estado = "";
        this.pollingTime = 1;
        this.larguraBandaNominal = 0;
        //numero de segundos a dividir pelo tempo entre pollings 
        this.ultimaHora = new ArrayList<PairTimeValue>();
        this.ultimoMinuto = new ArrayList<PairTimeValue>();
    }

    /**
     * @param oidInterface OID relativo a esta interface.
     * @param nome Nome da interface.
     * @param estado Estado da interface (”UP”ou ”DOWN”).
     * @param larguraBandaNominal Largura de Banda Nominal desta interface.
     * @param pollingTime Tempo de Polling feito ao agente.
     * @param ArrayList<PairTimeValue> ultimaHora Lista dos valores registados a cada tempo de polling, 
     *        usado para calcular a média, por hora, da largura de banda utilizada.
     * @param ArrayList<PairTimeValue> ultimoMinuto Lista dos valores registados a cada tempo de polling, 
     *        usado para calcular a mé́dia, por minuto, da largura de banda utilizada.
     */
    public DataInterface(int oidInterface, String nome, String estado, long larguraBandaNominal, float pollingTime, ArrayList<PairTimeValue> ultimaHora, ArrayList<PairTimeValue> ultimoMinuto) {
        this.oidInterface = oidInterface;
        this.nome = nome;
        this.estado = estado;
        this.pollingTime = pollingTime;
        this.larguraBandaNominal = larguraBandaNominal;
        //numero de segundos a dividir pelo tempo entre pollings 
        this.ultimaHora = ultimaHora;
        this.ultimoMinuto = ultimoMinuto;
    }

    //<editor-fold defaultstate="collapsed" desc="Gets">
    /**
     * 
     * @return
     */
    public int getOidInterface() {
        return oidInterface;
    }

    /**
     * 
     * @return
     */
    public String getNome() {
        return nome;
    }

    /**
     * 
     * @return
     */
    public String getEstado() {
        return estado;
    }

    /**
     * 
     * @return
     */
    public long getLarguraBandaNominal() {
        return larguraBandaNominal;
    }

    /**
     * 
     * @return
     */
    public float getPollingTime() {
        return pollingTime;
    }

    /**
     * 
     * @return
     */
    public long getTaxaBitsIntantaneaInput() {
        return updateTaxaBitsIntantaneaInput();
    }

    /**
     * 
     * @return
     */
    public long getTaxaBitsIntantaneaOutput() {
        return updateTaxaBitsIntantaneaOutput();
    }

    /**
     * 
     * @return
     */
    public ArrayList<PairTimeValue> getUltimaHora() {
        return ultimaHora;
    }

    /**
     * 
     * @return
     */
    public ArrayList<PairTimeValue> getUltimaHoraClone() {
        return ultimaHora;
    }

    /**
     * 
     * @return
     */
    public ArrayList<PairTimeValue> getUltimoMinuto() {
        return ultimoMinuto;
    }

    /**
     * 
     * @return
     */
    public ArrayList<PairTimeValue> getUltimoMinutoClone() {
        return ultimoMinuto;
    }
    //</editor-fold>

    //<editor-fold defaultstate="collapsed" desc="Sets">
    /**
     * 
     * @param oidInterface
     */
    public void setOidInterface(int oidInterface) {
        this.oidInterface = oidInterface;
    }

    /**
     * 
     * @param nome
     */
    public void setNome(String nome) {
        this.nome = nome;
    }

    /**
     * 
     * @param estado
     */
    public void setEstado(String estado) {
        this.estado = estado;
    }

    /**
     * 
     * @param larguraBandaNominal
     */
    public void setLarguraBandaNominal(long larguraBandaNominal) {
        this.larguraBandaNominal = larguraBandaNominal;
    }

    /**
     * 
     * @param pollingTime
     */
    public void setPollingTime(float pollingTime) {
        this.pollingTime = pollingTime;
    }

    /**
     * 
     * @param ultimaHora
     */
    public void setUltimaHora(ArrayList<PairTimeValue> ultimaHora) {
        this.ultimaHora = ultimaHora;
    }

    /**
     * 
     * @param ultimoMinuto
     */
    public void setUltimoMinuto(ArrayList<PairTimeValue> ultimoMinuto) {
        this.ultimoMinuto = ultimoMinuto;
    }
    //</editor-fold>

    /**
     * Adiciona novo valor aos arrays do ultimo minuto e última hora
     * @param valorOutput
     * @param valorInput
     */
    public void adicionarValor(long time, long valorOutput, long valorInput) {
        synchronized (ultimaHora) {
            this.ultimaHora.add(new PairTimeValue(time, valorOutput, valorInput));
            Collections.sort(ultimaHora, new PairTimeValue());
        }
            
        synchronized (ultimoMinuto) {
            this.ultimoMinuto.add(new PairTimeValue(time, valorOutput, valorInput));
            Collections.sort(ultimoMinuto, new PairTimeValue());
        }
    }

    /**
     * Remove dados que excederam o timeout do ultimo minuto
     */
    public void removerTimeOutedUltimoMinuto() {
        synchronized (this.ultimoMinuto) {
            //timeout do ultimo minuto
                for (int i = 0; i < this.ultimoMinuto.size(); i++) {
                    if ((this.ultimoMinuto.get(this.ultimoMinuto.size() - 1).getTime() - this.ultimoMinuto.get(i).getTime()) > 6000) {
                        //long x = (this.ultimoMinuto.get(this.ultimoMinuto.size()-1).getTime() - this.ultimoMinuto.get(i).getTime());
                        //System.out.println("Indice: " + i + "\nTempo: " + x + "\nArraySize: "+this.ultimoMinuto.size()+"\n");
                        this.ultimoMinuto.remove(i);
                    }
                }
                
                System.out.println("Size MIN: " + this.ultimoMinuto.size()+
                                   "Diferença: "+ (this.ultimoMinuto.get(this.ultimoMinuto.size() - 1).getTime() - this.ultimoMinuto.get(0).getTime()));
        }
    }

    /**
     * Remove dados que excederam o timeout da ultima hora
     */
    public void removerTimeOutedUltimaHora() {
        synchronized (this.ultimaHora) {
            //timeout da ultima hora
            for (int i = 0; i < this.ultimaHora.size(); i++) {
                if ((this.ultimaHora.get(this.ultimaHora.size() - 1).getTime() - this.ultimaHora.get(i).getTime()) > 60000) {
                    this.ultimaHora.remove(i);
                }
            }
        }
        System.out.println("Size Hora: " + this.ultimaHora.size()+
                            "Diferença: "+ (this.ultimaHora.get(this.ultimaHora.size() - 1).getTime() - this.ultimaHora.get(0).getTime()));

    }

    /**
     * Devolve a percentagem de utilização na última hora - Output
     * @return
     */
    public float percentagemUltimaHoraOutput() {
        long soma = 0;
        float media, percentagem = 0;

        this.removerTimeOutedUltimaHora();

        if (!this.ultimaHora.isEmpty()) {
            //soma dos valores
            for (int i = 0; i + 1 < this.ultimaHora.size(); i++) {
                soma += (this.ultimaHora.get(i + 1).getValueOutput() - this.ultimaHora.get(i).getValueOutput());
            }

            //calculo da média
            media = (soma / this.ultimaHora.size());

            //calculo da percentagem
            if (this.nome.startsWith("wlan")) {
                percentagem = (media / 54000000) * 100;
            } else {
                percentagem = (media / (this.larguraBandaNominal * (100000))) * 100;
            }
        }
        return (float) percentagem;
    }

    /**
     * Devolve a percentagem de utilização na última hora - Input
     * @return
     */
    public float percentagemUltimaHoraInput() {
        long soma = 0;
        float media, percentagem = 0;

        //remoção dos valores que já não pertencem à última hora
        this.removerTimeOutedUltimaHora();

        if (!this.ultimaHora.isEmpty()) {
            //soma dos valores
            for (int i = 0; i + 1 < this.ultimaHora.size(); i++) {
                soma += (this.ultimaHora.get(i + 1).getValueInput() - this.ultimaHora.get(i).getValueInput());
            }

            //calculo da média
            media = (soma / this.ultimaHora.size());

            //calculo da percentagem
            if (this.nome.startsWith("wlan")) {
                percentagem = (media / 54000000) * 100;
            } else {
                percentagem = (media / (this.larguraBandaNominal * (100000))) * 100;
            }
        }
        return (float) percentagem;
    }

    /**
     * Devolve a percentagem de utilização na último minuto - Output
     * @return
     */
    public float percentagemUltimoMinutoOutput() {
        long soma = 0;
        float media, percentagem = 0;

        //remoção dos valores que já não pertencem ao último minuto
        this.removerTimeOutedUltimoMinuto();

        if (!this.ultimoMinuto.isEmpty()) {
            //soma dos valores
            for (int i = 0; i + 1 < this.ultimoMinuto.size(); i++) {
                soma += (this.ultimoMinuto.get(i + 1).getValueOutput() - this.ultimoMinuto.get(i).getValueOutput());
            }

            //calculo da média
            media = (soma / this.ultimoMinuto.size());

            //calculo da percentagem
            if (this.nome.startsWith("wlan")) {
                percentagem = (media / 54000000) * 100;
            } else {
                percentagem = (media / (this.larguraBandaNominal * (100000))) * 100;
            }
        }
        return (float) percentagem;
    }

    /**
     * Devolve a percentagem de utilização na último minuto - Input
     * @return
     */
    public float percentagemUltimoMinutoInput() {
        long soma = 0;
        float media, percentagem = 0;

        this.removerTimeOutedUltimoMinuto();

        if (!this.ultimoMinuto.isEmpty()) {
            //soma dos valores
            for (int i = 0; i + 1 < this.ultimoMinuto.size(); i++) {
                soma += (this.ultimoMinuto.get(i + 1).getValueInput() - this.ultimoMinuto.get(i).getValueInput());
            }

            //calculo da média
            media = (soma / this.ultimoMinuto.size());

            //calculo da percentagem
            if (this.nome.startsWith("wlan")) {
                percentagem = (media / 54000000) * 100;
            } else {
                percentagem = (media / (this.larguraBandaNominal * (100000))) * 100;
            }
        }
        return (float) percentagem;
    }

    /**
     * Método que calcula a taxa de bits instantânea do Input
     * @return Devolve a taxa de bits actual de Output
     */
    private long updateTaxaBitsIntantaneaInput() {
        return (long)((this.ultimoMinuto.get(ultimoMinuto.size() - 1).getValueInput() - this.ultimoMinuto.get(ultimoMinuto.size() - 2).getValueInput())/pollingTime);
    }

    /**
     * Método que calcula a taxa de bits instantânea do Output
     * @return Devolve a taxa de bits actual de Output
     */
    private long updateTaxaBitsIntantaneaOutput() {
        return (long)((this.ultimoMinuto.get(ultimoMinuto.size() - 1).getValueOutput() - this.ultimoMinuto.get(ultimoMinuto.size() - 2).getValueOutput())/pollingTime);
    }
}
